iT邦幫忙

2023 iThome 鐵人賽

DAY 23
0
SideProject30

用30天打好Python、LineBot的基礎&基本應用系列 第 23

[Day 23] 將油價調漲(降)的資訊發送給使用者吧

  • 分享至 

  • xImage
  •  

前一天教了如何使用氣象局API來爬取天氣資訊,那今天也來個進階一點的吧!!爬取汽油資訊。

我們爬取的網站是GoodLife 油價預測,此處使用requests與beautifulsoup去爬取資訊。

程式碼範例如下

import requests
import json
import threading
import warnings
import subprocess

from bs4 import BeautifulSoup
from flask import Flask, request
from linebot.models import TextSendMessage
from linebot import LineBotApi, WebhookHandler, LineBotSdkDeprecatedIn30

def check_oil_price(user_id):
    #這邊記得修改
    api = LineBotApi('<你的channel access token>')
    #目標網址
    url = "https://gas.goodlife.tw/"
    price_array = []
    #輸出用
    output_keyword = [
        "92汽油",
        "95汽油",
        "98汽油",
    ]
    #搜尋網站元素關鍵字
    search_keyword = [
        "92:",
        "95油價:",
        "98:",
    ]
    #目前油價
    output_curr_price = ""
    #下週調整
    output_oli_price_adjust = ""

    html = requests.get(url)
    #此網站編碼使用ISO-8859-1需更改編碼為utf-8
    soup = BeautifulSoup(html.content, "html.parser", from_encoding='utf-8')

    #油價
    for i in search_keyword:
        price = soup.find(lambda tag:tag.name=='li' and i in tag.text)
        price = price.text.split("\n")
        price_array.append(price[2])

    #下周油價
    data = soup.find("li", class_="main").text.split()
    #網站可能的變化
    if len(data) == 3:
        output_oli_price_adjust = "從下周一起汽油每公升" + data[2]
    elif data[9] == "不":
        output_oli_price_adjust = "從今日起汽油每公升不調整"
    else:
        output_oli_price_adjust = "自"
        for i in range(1, 10):
            output_oli_price_adjust += data[i]
    
    #取得目前油價
    for i in range(3):
        output_curr_price += "目前" + output_keyword[i] + "價格:" + str(price_array[i]) + "\n"

    #傳送訊息給使用者
    api.push_message(user_id, TextSendMessage(text=output_curr_price))
    api.push_message(user_id, TextSendMessage(text=output_oli_price_adjust))


app = Flask(__name__)
@app.route("/", methods=['POST'])
def get_reply():
    handler = WebhookHandler('<你的channel secret>')
    body = request.get_data(as_text=True)
    json_data = json.loads(body)

    try:
        signature = request.headers['X-Line-Signature']
        handler.handle(body, signature)
        user_id = json_data['events'][0]["source"]['userId']
        text = json_data['events'][0]['message']['text']
        if text == "油價":
            check_oil_price(user_id)
    except Exception as e:
       print(e)
    return 'OK'

def jobs1():
	app.run()

#此處記得修改
def jobs2():
    subprocess.run([
        "ngrok", 
        "http", 
        "5000",
        "--domain=<你的domain網址>", 
        "--log=stdout"
    ])


if __name__ == "__main__":
    #避免出現警告訊息
    warnings.filterwarnings("ignore", category=LineBotSdkDeprecatedIn30)
    #使用多線程
    jobs = []
    jobs.append(threading.Thread(target=jobs1))
    jobs.append(threading.Thread(target=jobs2))

    for i in range(len(jobs)):
        jobs[i].start()

結果如下圖

https://ithelp.ithome.com.tw/upload/images/20231003/201465550mv3ZzBPVM.png


這邊多一種輸出寫法,將數字更改為貼圖,美化輸出

只需將60後的部分更改為下面演示的程式碼即可(不用覆蓋到app = Flask(__name__)的部分)

    emoji_output(user_id, api, output_curr_price)
    emoji_output(user_id, api, output_oli_price_adjust)

def emoji_output(user_id, api, message):
    output_emoji_dict = []
    #篩選是否含有0~9的字元
    for i in range(len(message)):
        if message[i] == '1':
            message = replace_emoji(i, "053", message, output_emoji_dict)
        elif message[i] == '2':
            message = replace_emoji(i, "054", message, output_emoji_dict)
        elif message[i] == '3':
            message = replace_emoji(i, "055", message, output_emoji_dict)
        elif message[i] == '4':
            message = replace_emoji(i, "056", message, output_emoji_dict)
        elif message[i] == '5':
            message = replace_emoji(i, "057", message, output_emoji_dict)
        elif message[i] == '6':
            message = replace_emoji(i, "058", message, output_emoji_dict)
        elif message[i] == '7':
            message = replace_emoji(i, "059", message, output_emoji_dict)
        elif message[i] == '8':
            message = replace_emoji(i, "060", message, output_emoji_dict)
        elif message[i] == '9':
            message = replace_emoji(i, "061", message, output_emoji_dict)
        elif message[i] == '0':
            message = replace_emoji(i, "062", message, output_emoji_dict)
        #想要修改的也可以自己新增喔,範本如下所示(記得把註解去掉)
        '''
        elif message[i] == '<想要修改的字元>':
            message = replace_emoji(i, <貼圖的索引>)
        '''
    #傳送訊息
    #記得TextSendMessage的emojis最高上限為單則留言20個貼圖喔
    api.push_message(user_id, TextSendMessage(text=message, emojis=output_emoji_dict))

def replace_emoji(for_index, emoji_id, target_array, output_emoji_dict):
    #作為範本使用
    data = {
        "index": -1,
        "productId": "5ac21a8c040ab15980c9b43f",
        "emojiId": "0"
    }
    data["index"] = for_index
    data["emojiId"] = emoji_id
    output_emoji_dict.append(data)
    #將字元修改為'$'符號
    return_str = target_array[:for_index] + '$' + target_array[for_index+1:]
    return return_str

效果如下圖

https://ithelp.ithome.com.tw/upload/images/20231003/20146555XG53pI2Hrp.png

Day 14有做詳細的解說,若有不懂可以跳轉連結去參考。

註:

油價調漲(降)可能隨著網站的變化而導致資訊跑掉,屆時需要再做修改


上一篇
[Day 22] 發送天氣預報結果給使用者吧
下一篇
[Day 24] 讓機器人也有想法!使用Bing image creator吧
系列文
用30天打好Python、LineBot的基礎&基本應用30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言